package extras.salvation.api.methods;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.net.URL;

import javax.imageio.ImageIO;

import com.rsbuddy.script.methods.Calculations;
import com.rsbuddy.script.methods.Game;
import com.rsbuddy.script.methods.Mouse;
import com.rsbuddy.script.util.Timer;
import com.rsbuddy.script.wrappers.GameObject;
import com.rsbuddy.script.wrappers.GroundItem;
import com.rsbuddy.script.wrappers.Model;
import com.rsbuddy.script.wrappers.Npc;
import com.rsbuddy.script.wrappers.Player;
import com.rsbuddy.script.wrappers.Projectile;
import com.rsbuddy.script.wrappers.Tile;

import extras.mak001.Time;
import extras.salvation.api.wrappers.SkillInformation;

/**
 * @author Salvation
 * @version 1.0
 * @since 20-08-2011
 * @see extras.salvation.api.wrappers.SkillInformation
 * @see extras.salvation.api.methods.ExtendedSkillInformation
 * @see extras.salvation.api.methods.ExtendedCalculations
 * 
 *      Next update will introduce dynamic placement of images, to allow
 *      Resizeable mode to work.
 **/
public final class ExtendedPaint {

	// Colours
	public static final Color PURPLE = new Color(128, 0, 128);
	public static final Color LIGHT_GREEN = new Color(0, 250, 154);
	public static final Color BROWN = new Color(92, 51, 23);
	public static final Color LIGHT_BROWN = new Color(139, 90, 43);
	public static final Color GOLD = new Color(255, 191, 0);

	// Variables used by the Mouse Listener
	private static boolean DREW_PAINT_BUTTON = false;
	private static boolean DREW_EXPERIENCE_BAR = false;
	private static boolean DRAW_EXTENDED_EXPERIENCE_BAR = false;
	private static boolean PAINT_ENABLED = true;

	// Rectangulars used by the Mouse Listener
	private static final Rectangle RECT_PAINT_BUTTON = new Rectangle(520, 465,
			30, 35);
	private static final Rectangle RECT_ABOVE_CHATBOX = new Rectangle(2, 319,
			514, 18);
	private static final Rectangle RECT_TOP_LEFT = new Rectangle(2, 4, 514, 18);
	private static Rectangle RECT_EXPERIENCE_BAR = new Rectangle(0, 0, 2, 2);

	// Timer
	private static long START_TIME;
	private static long RUN_TIME;

	// Progress Bar Parameters
	public static final int POSITION_ABOVE_CHATBOX = 0;
	public static final int POSITION_TOP_LEFT = 1;

	// Mouse Parameters
	public static final int MOUSE_STYLE_CROSSHAIR = 0;

	// RenderingHints
	public static final RenderingHints ANTIALIASING = new RenderingHints(
			RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

	// Images
	private static final Image IMAGE_PAINT_BUTTON = getImage("http://mak001.x10.mx/Pics/paint_button.png");
	private static final Image IMAGE_INVENTORY = getImage("http://mak001.x10.mx/Pics/inventory.png");
	private static final Image IMAGE_SALVATION = getImage("http://mak001.x10.mx/Pics/salvation2.png");

	// Fonts
	private static final Font FONT = new Font("Arial", Font.BOLD, 12);
	public static final int FONT_STYLE_REGULAR = 0;
	public static final int FONT_STYLE_SHADOW = 1;
	public static final int FONT_STYLE_OUTLINE = 2;

	// Boundaries
	@SuppressWarnings("unused")
	private static final int GAME_WIDTH = 1337;
	@SuppressWarnings("unused")
	private static final int GAME_HEIGHT = 1337;

	private static final int[] BOUNDARIES_ABOVE_CHATBOX = { 2, 319, 514, 18, 3,
			320, 513, 17, 3, 320, 513, 17, 3, 320, 513, 17, 10, 333 };

	private static final int[] BOUNDARIES_TOP_LEFT = { 2, 4, 514, 18, 3, 5,
			513, 17, 3, 5, 513, 17, 3, 5, 513, 17, 10, 18 };

	private static final int[] BOUNDARIES_EXTENDED_ABOVE_CHATBOX = { 2, 0, 222,
			225, 3, 1, 221, 224, 10, 15 };

	private static final int[] BOUNDARIES_EXTENDED_TOP_LEFT = { 2, 23, 222,
			225, 3, 24, 221, 224, 10, 40 };

	private static final int[] BOUNDARIES_INVENTORY = { 6, 345, 506, 128, 7,
			346, 505, 127, 7, 346, 505, 127, 7, 346, 505, 127, 10, 360, 65,
			360, 480, 450 };

	/**
	 * @author Salvation
	 * @param url
	 *            The URL of the image, as String.
	 * @return The image gotten from the URL.
	 */
	public static Image getImage(String url) {
		try {
			return ImageIO.read(new URL(url));
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * @author Salvation
	 * @description Starts all crucial methods needed to run the paint.
	 * @see ExtendedSkillInformation.reset()
	 * @see setStartTime()
	 */
	public static void start() {
		ExtendedSkillInformation.reset();
		setStartTime();
	}

	/**
	 * @author Salvation
	 * @description Sets a start time for the script.
	 * @see getRunTime()
	 */
	public static void setStartTime() {
		START_TIME = System.currentTimeMillis();
	}

	public static long getStartTime() {
		return START_TIME;
	}

	/**
	 * @author Salvation
	 * @return The time the script has ran since the timer was set.
	 * @see setStartTime()
	 */
	public static long getRunTime() {
		RUN_TIME = System.currentTimeMillis() - START_TIME;
		return RUN_TIME != 0 ? RUN_TIME : 1;
	}

	/**
	 * @author Salvation
	 * @return The time the script has ran since the timer was set, formatted
	 *         using hh:mm:ss.
	 * @see setStartTime()
	 */
	public static String getRunTimeFormatted(Time time) {
		if (time == null)
			return Timer.format(getRunTime());
		else
			return Timer.format(time.currTime());
	}

	/**
	 * @author Salvation
	 * @param g
	 *            The canvas to edit.
	 */
	public static void enableAntiAliasing(final Graphics2D g) {
		if (PAINT_ENABLED)
			g.setRenderingHints(ANTIALIASING);
	}

	/**
	 * @author Salvation
	 * @description Draws the paint button needed to hide/show the paint
	 * @param g
	 *            The canvas to paint on.
	 */
	public static void drawPaintButton(final Graphics2D g) {
		DREW_PAINT_BUTTON = true;
		g.drawImage(IMAGE_PAINT_BUTTON, 527, 475, null);
	}

	/**
	 * @author Salvation
	 * @description Show the author of ExtendedPaint a bit of love, draw his
	 *              image on top of the chatbox!
	 * @param g
	 *            The canvas to paint on
	 */
	public static void drawSalvation(final Graphics2D g) {
		if (PAINT_ENABLED)
			g.drawImage(IMAGE_SALVATION, 0, 0, null);
	}

	/**
	 * @author Salvation
	 * @description Uses the MouseListener from the ActiveScript as input,
	 *              parses drawn objects and checks what needs to be done.
	 * @param m
	 *            The MouseEvent from a Listener in the ActiveScript.
	 */
	public static void mouseClicked(final MouseEvent m) {
		final Point p = m.getPoint();
		if (DREW_PAINT_BUTTON && RECT_PAINT_BUTTON.contains(p))
			PAINT_ENABLED = !PAINT_ENABLED;
	}

	/**
	 * @author Salvation
	 * @description Uses the MouseListener from the ActiveScript as input,
	 *              parses drawn objects and checks what needs to be done.
	 * @param m
	 *            The MouseEvent from a Listener in the ActiveScript.
	 */
	public static void mouseMoved(final MouseEvent m) {
		final Point p = m.getPoint();
		if (DREW_EXPERIENCE_BAR)
			DRAW_EXTENDED_EXPERIENCE_BAR = RECT_EXPERIENCE_BAR.contains(p);
	}

	/**
	 * @author Salvation
	 * @param object
	 *            The Object to format.
	 * @return A formatted String of the Object.
	 */
	public static String format(final Object object) {
		String s = object.toString();
		final int length = s.length();
		if (length < 4)
			return s;

		for (int i = length - 3; i > 0; i -= 3) {
			s = s.substring(0, i) + "," + s.substring(i);
		}
		return s;
	}

	/**
	 * @author Salvation
	 * @param value
	 *            The value to format.
	 * @return A formatted value of x...k or x.
	 */
	public static String formatValue(int value) {
		if (value >= 1000) {
			value += 500;
			return Integer.toString((int) value / 1000) + "k";
		}
		return Integer.toString(value);
	}

	/**
	 * @author Salvation
	 * @param string
	 * @param style
	 * @param x
	 * @param y
	 */
	public static void drawString(final Graphics2D g, final String message,
			final int style, final Color colorRegular,
			final Color colorSpecial, final int x, final int y) {
		final Color color = g.getColor();
		final Font font = g.getFont();

		if (style == FONT_STYLE_SHADOW) {
			g.setColor(colorSpecial);
			g.drawString(message, x + 1, y + 1);
			g.setColor(colorRegular);
			g.drawString(message, x, y);
		} else if (style == FONT_STYLE_OUTLINE) {
			g.setColor(colorRegular);
			g.drawString(message, x - 1, y - 1);
			g.drawString(message, x - 1, y + 1);
			g.drawString(message, x + 1, y - 1);
			g.drawString(message, x + 1, y + 1);
			g.setColor(colorSpecial);
			g.drawString(message, x, y);
		}

		resetComposite(g, color, font);
	}

	/**
	 * @author Salvation
	 * @param g
	 *            The canvas to paint on.
	 * @param position
	 *            The type of experience bar, defining location and size.
	 * @param style
	 *            The style of the experience bar.
	 * @param skill
	 *            The skill the experience bar should show.
	 */
	public static void drawProgressBar(final Graphics2D g, final int position,
			final int skill) {
		final SkillInformation si = ExtendedSkillInformation
				.getSkillInfomation(skill);
		if (!PAINT_ENABLED)
			return;
		if (si.getSkill() == 25)
			return;
		DREW_EXPERIENCE_BAR = true;

		final Color color = g.getColor();
		final Font font = g.getFont();
		final int[] array = getArrayFromPosition(position);

		g.setFont(FONT);
		drawRectangular(g, array);
		fillRectangular(g, array);
		fillProgress(g, array, si.getPercentToNextLevel(), si.getColor());
		drawText(g, array, si);
		drawExtendedExperienceBar(g, si, position, skill);
		resetComposite(g, color, font);
	}

	/**
	 * @author Salvation
	 * @param g
	 *            The canvas to paint on.
	 * @param style
	 *            The style for this paint.
	 * @param skill
	 *            The skill which should be shown.
	 */
	public static void drawInventory(final Graphics2D g, final int skill) {
		if (!PAINT_ENABLED)
			return;

		final SkillInformation si = ExtendedSkillInformation
				.getSkillInfomation(skill);
		final Color color = g.getColor();
		final Font font = g.getFont();
		g.setFont(FONT);

		drawInventoryImage(g);
		drawInventoryRectangular(g);
		fillInventoryShade(g, si.getColor());
		drawInventoryText(g, si, null);
		resetComposite(g, color, font);
	}

	/**
	 * limit of 8 Strings
	 * 
	 * @author Salvation
	 * @param g
	 *            The canvas to paint on.
	 * @param messages
	 *            The text to show.
	 */
	public static void drawExtraInventory(final Graphics2D g, final int skill,
			final String[] messages) {
		final SkillInformation si = ExtendedSkillInformation
				.getSkillInfomation(skill);
		final Color color = g.getColor();
		final Font font = g.getFont();
		if (PAINT_ENABLED) {
			g.setFont(FONT);

			g.setColor(si.getFontColor());
			for (int i = 0; i < messages.length; i++) {
				g.drawString(messages[i], BOUNDARIES_INVENTORY[16] + 200,
						BOUNDARIES_INVENTORY[17] + i * 15);
			}

			resetComposite(g, color, font);
		}
	}

	/**
	 * @author Salvation
	 * @param g
	 *            The canvas to paint on.
	 * @param type
	 *            The type of mouse to be shown.
	 * @param message
	 *            An option message to show next to the mouse, only for
	 *            MOUSE_CROSSHAIR and sub-variants!
	 */
	public static void drawMouse(final Graphics2D g, final int type,
			final int skill, final int style, final String message) {
		if (!Mouse.isPresent() || !PAINT_ENABLED)
			return;

		final SkillInformation si = ExtendedSkillInformation
				.getSkillInfomation(skill);
		final Color color = g.getColor();
		final Font font = g.getFont();
		final Point loc = Mouse.getLocation();
		final Dimension size = Game.getCanvasSize();
		final int width = (int) size.getWidth();
		final int height = (int) size.getHeight();

		if (type == MOUSE_STYLE_CROSSHAIR) {
			g.setFont(FONT);
			g.setColor(si.getFontColor());
			g.fill(new Rectangle(0, loc.y - 1, width, 3));
			g.fill(new Rectangle(loc.x - 1, 0, 3, height));

			if (style > FONT_STYLE_REGULAR) {
				drawString(g, message, style, si.getFontColor(), si.getColor(),
						loc.x + 5, loc.y - 5);
			} else {
				g.drawString(message, loc.x + 5, loc.y - 5);
			}

			g.setColor(si.getColor());

			g.drawLine(0, loc.y, width, loc.y);
			g.drawLine(loc.x, 0, loc.x, height);
		}

		resetComposite(g, color, font);
	}

	/**
	 * @author Salvation
	 * @param g
	 *            The canvas to paint on.
	 * @param tile
	 *            The Tile to paint.
	 * @param outline
	 *            The outline of the Tile, null to disable the drawing of an
	 *            outline.
	 * @param fill
	 *            The fill of the Tile, null to disable to drawing of the fill.
	 * @see drawTilesToScreen()
	 */
	@SuppressWarnings("deprecation")
	public static void drawTileToScreen(final Graphics2D g, final Tile tile,
			final Color outline, final Color fill) {
		if (tile == null || !tile.isOnScreen()
				|| (outline == null && fill == null))
			return;

		final Color color = g.getColor();
		final Font font = g.getFont();

		final Tile tileSouthWest = tile;
		final Tile tileSouthEast = new Tile(tile.getX() + 1, tile.getY());
		final Tile tileNorthEast = new Tile(tile.getX() + 1, tile.getY() + 1);
		final Tile tileNorthWest = new Tile(tile.getX(), tile.getY() + 1);

		final Point pointSouthWest = Calculations.tileToScreen(tileSouthWest,
				0, 0, 0);
		final Point pointSouthEast = Calculations.tileToScreen(tileSouthEast,
				0, 0, 0);
		final Point pointNorthEast = Calculations.tileToScreen(tileNorthEast,
				0, 0, 0);
		final Point pointNorthWest = Calculations.tileToScreen(tileNorthWest,
				0, 0, 0);

		final int[] x = { pointSouthWest.x, pointSouthEast.x, pointNorthEast.x,
				pointNorthWest.x };
		final int[] y = { pointSouthWest.y, pointSouthEast.y, pointNorthEast.y,
				pointNorthWest.y };

		if (ExtendedArrays.contains(x, -1) || ExtendedArrays.contains(y, -1))
			return;

		final Polygon p = new Polygon(x, y, 4);

		if (outline != null) {
			g.setColor(outline);
			g.drawPolygon(p);
		}

		if (fill != null) {
			g.setColor(fill);
			g.fillPolygon(p);
		}

		resetComposite(g, color, font);
	}

	/**
	 * @author Salvation
	 * @param g
	 *            The canvas to paint on.
	 * @param tiles
	 *            An array of Tile to be painted.
	 * @param outline
	 *            The outline of the Tile, null to disable the drawing of an
	 *            outline.
	 * @param fill
	 *            The fill of the Tile, null to disable to drawing of the fill.
	 * @see drawTileToScreen()
	 */
	public static void drawTilesToScreen(final Graphics2D g,
			final Color outline, final Color fill, final Tile... tiles) {
		if (tiles == null)
			return;
		for (final Tile t : tiles) {
			if (t == null)
				return;
			drawTileToScreen(g, t, outline, fill);
		}
	}

	/**
	 * @author Salvation
	 * @description Draws text to the specified title.
	 * @param g
	 *            The canvas to paint on.
	 * @param tile
	 *            The Tile where the text should be paint on.
	 * @param colorFont
	 *            The color for the font.
	 * @param lines
	 *            One or more Strings to be written
	 */
	public static void drawTextToTile(final Graphics2D g, final Tile tile,
			final Color colorFont, final String... lines) {
		if (tile == null || !tile.isOnScreen() || colorFont == null
				|| lines == null)
			return;

		final Color color = g.getColor();
		final Font font = g.getFont();
		final int length = lines.length;
		final Point point = tile.getCenterPoint();
		final Point p = new Point(point.x, point.y - (length / 2));

		g.setColor(colorFont);

		for (int i = 0; i < length; i++) {
			g.drawString(lines[i], p.x, p.y + i * 15);
		}

		resetComposite(g, color, font);
	}

	/**
	 * @author Salvation
	 * @param g
	 *            The canvas to paint on.
	 * @param object
	 *            The Object to draw the Model of.
	 * @param outline
	 *            The wireframes to be drawn, null to disable.
	 * @param fill
	 *            The entire model to be filled with, null to disable.
	 */
	public static void drawModel(final Graphics2D g, final Object object,
			final Color outline, final Color fill) {
		final Model m = getModel(object);
		if (m == null)
			return;

		final Color color = g.getColor();
		final Font font = g.getFont();

		if (fill != null) {
			final Polygon[] polygon = m.getTriangles();
			g.setColor(fill);
			for (Polygon p : polygon) {
				g.fillPolygon(p);
			}
		}

		if (outline != null) {
			g.setColor(outline);
			m.drawWireFrame(g);
		}

		resetComposite(g, color, font);
	}

	/**
	 * @author Salvation
	 * @description Start of private methods, to be used by public methods.
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 */

	private static void drawExtendedExperienceBar(final Graphics2D g,
			final SkillInformation si, final int position, final int skill) {
		if (si.getSkill() == 25)
			return;
		if (!DRAW_EXTENDED_EXPERIENCE_BAR)
			return;
		final int[] array = RECT_EXPERIENCE_BAR.equals(RECT_ABOVE_CHATBOX) ? BOUNDARIES_EXTENDED_ABOVE_CHATBOX
				: BOUNDARIES_EXTENDED_TOP_LEFT;

		drawExtendedRectangular(g, array);
		fillExtendedRectangular(g, array, si.getColor());
		drawExtendedText(g, si, array);
	}

	private static void drawRectangular(final Graphics2D g, final int[] array) {
		g.setColor(Color.BLACK);
		g.drawRect(array[0], array[1], array[2], array[3]);
	}

	private static void fillRectangular(final Graphics2D g, final int[] array) {
		g.setColor(Color.DARK_GRAY);
		g.fillRect(array[4], array[5], array[6], array[7]);
	}

	private static void fillProgress(final Graphics2D g, final int[] array,
			final int percent, final Color color) {
		final Point a = new Point(array[12], array[13]);
		final Point b = new Point(array[12], array[13] + array[15] / 2);
		final Rectangle r = new Rectangle(array[12], array[13], (int) (percent
				* array[10] / 100.0), array[15]);
		final GradientPaint gp = new GradientPaint(a, down(color, 50, 200), b,
				down(color, 0, 200), true);
		g.setPaint(gp);
		g.fill(r);
	}

	private static void drawText(final Graphics2D g, final int[] array,
			final SkillInformation si) {
		if (si.getSkill() != 25) {
			g.setColor(si.getFontColor());
			g.drawString(Timer.format(si.getTimeToLevel()) + ", "
					+ si.getPercentToNextLevel() + "% or "
					+ ((si.getExperienceToNextLevel() + 500) / 1000)
					+ "k experience to level " + (si.getCurrentLevel() + 1)
					+ " in " + si.getName() + " at "
					+ (si.getGainedExperienceHour() + 500) / 1000 + "k xp/h",
					array[16], array[17]);
		}
	}

	private static void drawExtendedRectangular(final Graphics2D g,
			final int[] array) {
		g.setColor(Color.BLACK);
		g.drawRect(array[0], array[1], array[2], array[3]);
	}

	private static void fillExtendedRectangular(final Graphics2D g,
			final int[] array, final Color color) {
		final Point a = new Point(array[4], array[5]);
		final Point b = new Point(array[4], array[5] + array[7] / 2);
		final Rectangle r = new Rectangle(array[4], array[5], array[6],
				array[7]);
		final GradientPaint gp = new GradientPaint(a, down(color, 50, 155), b,
				down(color, 0, 155), true);
		g.setPaint(gp);
		g.fill(r);
	}

	private static void drawExtendedText(final Graphics2D g,
			final SkillInformation si, final int[] array) {
		g.setColor(si.getFontColor());
		g
				.drawString("Skill Name: " + si.getName(), array[8],
						array[9] + 0 * 15);
		if (si.getSkill() != 26) {
			g.drawString("Start Experience: " + si.getStartExperience(),
					array[8], array[9] + 1 * 15);
			g.drawString("Current Experience: " + si.getCurrentExperience(),
					array[8], array[9] + 2 * 15);
			g.drawString("Gained Experience: " + si.getGainedExperience(),
					array[8], array[9] + 3 * 15);
			g.drawString(
					"Experience per Hour: " + si.getGainedExperienceHour(),
					array[8], array[9] + 4 * 15);
			g.drawString("Start Level: " + si.getStartLevel(), array[8],
					array[9] + 5 * 15);
			g.drawString("Current Level: " + si.getCurrentLevel(), array[8],
					array[9] + 6 * 15);
			g.drawString("Gained Levels: " + si.getGainedLevel(), array[8],
					array[9] + 7 * 15);
			g.drawString("Experience to Next Level: "
					+ si.getExperienceToNextLevel(), array[8],
					array[9] + 8 * 15);
			g.drawString("Percentage to Next Level: "
					+ si.getPercentToNextLevel(), array[8], array[9] + 9 * 15);
			g.drawString("Time to Next Level: "
					+ Timer.format(si.getTimeToLevel()), array[8],
					array[9] + 10 * 15);
			g.drawString("Experience to Level 99: " + si.getExperienceTo99(),
					array[8], array[9] + 11 * 15);
			g.drawString("Percentage to Level 99: " + si.getPercentTo99(),
					array[8], array[9] + 12 * 15);
			g.drawString("Time to Level 99: " + Timer.format(si.getTimeTo99()),
					array[8], array[9] + 13 * 15);
		}
	}

	private static void drawInventoryImage(final Graphics2D g) {
		g.drawImage(IMAGE_INVENTORY, 0, 0, null);
	}

	private static void drawInventoryRectangular(final Graphics2D g) {
		g.setColor(Color.BLACK);
		g.drawRect(BOUNDARIES_INVENTORY[0], BOUNDARIES_INVENTORY[1],
				BOUNDARIES_INVENTORY[2], BOUNDARIES_INVENTORY[3]);
	}

	private static void fillInventoryShade(final Graphics2D g, final Color color) {
		final Point a = new Point(BOUNDARIES_INVENTORY[18],
				BOUNDARIES_INVENTORY[19]);
		final Point b = new Point(BOUNDARIES_INVENTORY[20],
				BOUNDARIES_INVENTORY[21]);
		final Rectangle r = new Rectangle(BOUNDARIES_INVENTORY[4],
				BOUNDARIES_INVENTORY[5], BOUNDARIES_INVENTORY[6],
				BOUNDARIES_INVENTORY[7]);
		final GradientPaint gp = new GradientPaint(a, down(color, 0, 235), b,
				down(color, 100, 200));
		g.setPaint(gp);
		g.fill(r);
	}

	private static void drawInventoryText(final Graphics2D g,
			final SkillInformation si, Time time) {
		final String runTime = "Runtime: " + getRunTimeFormatted(time);
		if (si.getSkill() == 25) {
			g.setColor(si.getFontColor());
			g.drawString(runTime, BOUNDARIES_INVENTORY[16],
					BOUNDARIES_INVENTORY[17]);
		} else {
			final String lvl = "Level: " + formatValue(si.getCurrentLevel())
					+ " (" + formatValue(si.getStartLevel()) + " + "
					+ formatValue(si.getGainedLevel()) + ") in " + si.getName();
			final String exp = "Experience Gained: "
					+ formatValue(si.getGainedExperience()) + " ("
					+ formatValue(si.getGainedExperienceHour()) + " xp/h)";
			final String expNext = "Experience to Next Level: "
					+ formatValue(si.getExperienceToNextLevel());
			final String exp99 = "Experience to Level 99: "
					+ formatValue(si.getExperienceTo99());
			final String timeNext = "Time to Next Level: "
					+ Timer.format(si.getTimeToLevel());
			final String time99 = "Time to Level 99: "
					+ Timer.format(si.getTimeTo99());
			final String[] s = { runTime, lvl, exp, expNext, exp99, timeNext,
					time99 };

			g.setColor(si.getFontColor());
			for (int i = 0; i < s.length; i++) {
				g.drawString(s[i], BOUNDARIES_INVENTORY[16],
						BOUNDARIES_INVENTORY[17] + i * 15);
			}
		}
	}

	private static void resetComposite(final Graphics2D g, final Color color,
			final Font font) {
		g.setColor(color);
		g.setFont(font);
	}

	@SuppressWarnings("unused")
	private static Color up(final Color after, final Color original,
			final int alpha) {
		final int red = (after.getRed() + original.getRed()) / 2;
		final int green = (after.getGreen() + original.getGreen()) / 2;
		final int blue = (after.getBlue() + original.getBlue()) / 2;
		return new Color(red, green, blue, alpha);
	}

	private static Color down(final Color c, final int count, final int alpha) {
		final int red = c.getRed() - count < 0 ? 0 : c.getRed() - count;
		final int green = c.getGreen() - count < 0 ? 0 : c.getGreen() - count;
		final int blue = c.getBlue() - count < 0 ? 0 : c.getBlue() - count;
		return new Color(red, green, blue, alpha);
	}

	private static int[] getArrayFromPosition(final int position) {
		switch (position) {
		case POSITION_ABOVE_CHATBOX:
			RECT_EXPERIENCE_BAR = RECT_ABOVE_CHATBOX;
			return BOUNDARIES_ABOVE_CHATBOX;
		case POSITION_TOP_LEFT:
			RECT_EXPERIENCE_BAR = RECT_TOP_LEFT;
			return BOUNDARIES_TOP_LEFT;
		}
		RECT_EXPERIENCE_BAR = RECT_ABOVE_CHATBOX;
		return BOUNDARIES_ABOVE_CHATBOX;
	}

	private static Model getModel(final Object object) {
		if (object instanceof Npc) {
			return ((Npc) object).getModel();
		} else if (object instanceof GameObject) {
			return ((GameObject) object).getModel();
		} else if (object instanceof GroundItem) {
			return ((GroundItem) object).getModel();
		} else if (object instanceof Player) {
			return ((Player) object).getModel();
		} else if (object instanceof Projectile) {
			return ((Projectile) object).getModel();
		}
		return null;
	}

	public static void drawInventory(Graphics2D g, int skill, Time time) {
		if (!PAINT_ENABLED)
			return;

		final SkillInformation si = ExtendedSkillInformation
				.getSkillInfomation(skill);
		final Color color = g.getColor();
		final Font font = g.getFont();
		g.setFont(FONT);

		drawInventoryImage(g);
		drawInventoryRectangular(g);
		fillInventoryShade(g, si.getColor());
		drawInventoryText(g, si, time);
		resetComposite(g, color, font);
	}
}